"""
用户服务
处理用户相关的业务逻辑
"""
from typing import Optional
from fastapi import HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.user import User
from app.schemas.user import UserCreate, UserUpdate, UserLogin
from app.repositories.user import user_repository
from app.core.security import (
    get_password_hash, 
    verify_password, 
    create_token_pair
)


class UserService:
    """用户服务"""
    
    def __init__(self):
        self.repository = user_repository
    
    async def create_user(self, db: AsyncSession, *, user_create: UserCreate) -> User:
        """
        创建用户
        Args:
            db: 数据库会话
            user_create: 用户创建数据
        Returns:
            创建的用户对象
        Raises:
            HTTPException: 用户名或邮箱已存在
        """
        # 检查用户名是否已存在
        if await self.repository.is_username_taken(db, username=user_create.username):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="用户名已存在"
            )
        
        # 检查邮箱是否已存在
        if await self.repository.is_email_taken(db, email=user_create.email):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="邮箱已存在"
            )
        
        # 创建用户(密码已在repository中哈希)
        user_data = user_create.dict()
        user_data["password_hash"] = get_password_hash(user_data.pop("password"))
        
        # 使用字典创建用户
        user = User(**user_data)
        db.add(user)
        await db.commit()
        await db.refresh(user)
        
        return user
    
    async def authenticate_user(
        self, 
        db: AsyncSession, 
        *, 
        username_or_email: str, 
        password: str
    ) -> Optional[User]:
        """
        认证用户
        Args:
            db: 数据库会话
            username_or_email: 用户名或邮箱
            password: 密码
        Returns:
            认证成功的用户对象或None
        """
        user = await self.repository.get_by_username_or_email(
            db, identifier=username_or_email
        )
        
        if not user:
            return None
        
        if not verify_password(password, user.password_hash):
            return None
        
        if not user.is_active:
            return None
        
        return user
    
    async def login(
        self, 
        db: AsyncSession, 
        *, 
        login_data: UserLogin
    ) -> dict:
        """
        用户登录
        Args:
            db: 数据库会话
            login_data: 登录数据
        Returns:
            包含令牌的字典
        Raises:
            HTTPException: 认证失败或用户未激活
        """
        user = await self.authenticate_user(
            db, 
            username_or_email=login_data.username, 
            password=login_data.password
        )
        
        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的用户名或密码",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        # 更新最后登录时间
        from datetime import datetime
        user.last_login = datetime.utcnow()
        db.add(user)
        await db.commit()
        
        # 创建令牌对
        token_data = create_token_pair(user.id)
        
        return {
            **token_data,
            "user": user
        }
    
    async def get_user_by_id(self, db: AsyncSession, *, user_id: int) -> Optional[User]:
        """
        根据ID获取用户
        Args:
            db: 数据库会话
            user_id: 用户ID
        Returns:
            用户对象或None
        """
        return await self.repository.get(db, id=user_id)
    
    async def get_user_by_username(
        self, 
        db: AsyncSession, 
        *, 
        username: str
    ) -> Optional[User]:
        """
        根据用户名获取用户
        Args:
            db: 数据库会话
            username: 用户名
        Returns:
            用户对象或None
        """
        return await self.repository.get_by_username(db, username=username)
    
    async def update_user(
        self, 
        db: AsyncSession, 
        *, 
        user_id: int, 
        user_update: UserUpdate
    ) -> User:
        """
        更新用户
        Args:
            db: 数据库会话
            user_id: 用户ID
            user_update: 更新数据
        Returns:
            更新后的用户对象
        Raises:
            HTTPException: 用户不存在
        """
        user = await self.repository.get(db, id=user_id)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        
        return await self.repository.update(db, db_obj=user, obj_in=user_update)
    
    async def delete_user(self, db: AsyncSession, *, user_id: int) -> User:
        """
        删除用户
        Args:
            db: 数据库会话
            user_id: 用户ID
        Returns:
            删除的用户对象
        Raises:
            HTTPException: 用户不存在
        """
        user = await self.repository.get(db, id=user_id)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        
        return await self.repository.delete(db, id=user_id)
    
    async def change_password(
        self, 
        db: AsyncSession, 
        *, 
        user_id: int, 
        current_password: str, 
        new_password: str
    ) -> User:
        """
        修改密码
        Args:
            db: 数据库会话
            user_id: 用户ID
            current_password: 当前密码
            new_password: 新密码
        Returns:
            更新后的用户对象
        Raises:
            HTTPException: 用户不存在或当前密码错误
        """
        user = await self.repository.get(db, id=user_id)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        
        if not verify_password(current_password, user.password_hash):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="当前密码错误"
            )
        
        user.password_hash = get_password_hash(new_password)
        db.add(user)
        await db.commit()
        await db.refresh(user)
        
        return user
    
    async def refresh_token(
        self, 
        db: AsyncSession, 
        *, 
        refresh_token: str
    ) -> dict:
        """
        刷新令牌
        Args:
            db: 数据库会话
            refresh_token: 刷新令牌
        Returns:
            新的令牌对
        Raises:
            HTTPException: 令牌无效或用户不存在
        """
        from app.core.security import verify_refresh_token
        
        user_id = verify_refresh_token(refresh_token)
        if not user_id:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的刷新令牌",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        user = await self.repository.get(db, id=int(user_id))
        if not user or not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户不存在或已禁用",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        # 创建新的令牌对
        return create_token_pair(user.id)


# 创建服务实例
user_service = UserService()